//
// Created by ldh on 22-6-8.
//

#include "tracing.h"
#include <chrono>
#include <fstream>
#include <iostream>
#include <utility>
#include <filesystem>

namespace cpp_visual {
namespace json_tool {
nlohmann::json &get_json_parser() {
  static nlohmann::json j;
  return j;
}
std::size_t get_json_size() { return get_json_parser().size(); }
std::string get_json_str(int index) {
  return get_json_parser().at(index).dump();
}
void json_clear() { get_json_parser().clear(); }

std::string gen_json(const std::string &json_path) {
  std::ofstream of_json(json_path);
  of_json << get_json_parser();
  std::cout << get_json_parser().dump() << std::endl;
  return json_path;
}

} // namespace json_tool

int64_t TracingTool::start_time_ =
    std::chrono::duration_cast<std::chrono::microseconds>(
        std::chrono::system_clock::now().time_since_epoch())
        .count();
TracingConfig TracingTool::conf_;
bool TracingTool::start_{false};

int64_t TracingTool::currentDurationTs() {
  auto d = std::chrono::system_clock::now().time_since_epoch();
  auto ts = std::chrono::duration_cast<std::chrono::microseconds>(d).count();
  return ts - start_time_;
}
bool TracingTool::loadTracingConf(const std::string& conf_path) {
  std::ifstream in(conf_path);
  nlohmann::json conf_json;
  in >> conf_json;
  conf_json["enable"].get_to(conf_.enable);
  conf_json["tracing_json_path"].get_to(conf_.tracing_json_path);
  conf_json["max_cache"].get_to(conf_.max_cache);
  in.close();
  return false;
}
void TracingTool::setTracingConf(TracingConfig tracingConf) {
  conf_ = std::move(tracingConf);
}
const TracingConfig &TracingTool::getTracingConf() { return conf_; }
void TracingTool::writeJson(const std::string& json_str) {
  std::filesystem::path json_path(conf_.tracing_json_path);
  if(std::filesystem::exists(json_path.parent_path())) {
    std::filesystem::create_directories(json_path.parent_path());
  }

  std::ofstream  outs;
  //首次进入 删除遗留文件
  if(!start_) {
    if(std::filesystem::exists(conf_.tracing_json_path)) {
      std::filesystem::remove(conf_.tracing_json_path);
    }
  }
  //以追加方式打开文件
  outs.open(conf_.tracing_json_path, std::ios_base::app);
  if(!start_) {
    outs << "[";
    start_ = true;
  }
  //支持不完整的json 因此不必考虑闭合json
  outs << json_str << ",";
}
void TracingTool::finish() {
  for (int i = 0; i < json_tool::get_json_size(); ++i) {
    TracingTool::writeJson(json_tool::get_json_str(i));
  }
  json_tool::json_clear();
}

void TracingEvent::commitEvent() {
  if (!TracingTool::getTracingConf().enable) {
    return;
  }

  json_tool::get_json_parser().push_back(event_json_);
  if (json_tool::get_json_size() >= TracingTool::getTracingConf().max_cache) {
    for (int i = 0; i < json_tool::get_json_size(); ++i) {
      TracingTool::writeJson(json_tool::get_json_str(i));
    }
    json_tool::json_clear();
  }
}

TracingDuration::TracingDuration(const std::string &task_name,
                                 const std::string &thread_name,
                                 const std::string &duration_name) {
  setEventField("pid", task_name);
  setEventField("tid", thread_name);
  setEventField("name", duration_name);
}
void TracingDuration::begin() {
  setEventField("ph", "B");
  setEventField("ts", TracingTool::currentDurationTs());
  commitEvent();
}
void TracingDuration::end() {
  setEventField("ph", "E");
  setEventField("ts", TracingTool::currentDurationTs());
  commitEvent();
}

} // namespace cpp_visual